package com.steven.ourcontest.net.websocket

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import com.google.gson.Gson
import com.google.gson.JsonParser
import com.steven.ourcontest.chat.bean.WSAccountBan
import com.steven.ourcontest.chat.bean.WSApplyFriendResponse
import com.steven.ourcontest.chat.bean.WSChatOnlineMessageResponse
import com.steven.ourcontest.chat.bean.WSMessageResponse
import com.steven.ourcontest.chat.helper.MessageHelper
import com.steven.ourcontest.net.websocket.WebSocketService.MyWebSocketServiceBinder
import com.steven.ourcontest.utils.RxBus
import com.steven.ourcontest.utils.WebSocketOpen
import org.java_websocket.handshake.ServerHandshake
import java.nio.channels.NotYetConnectedException

class WebSocketAndroidClient private constructor(
    private val mContext: Context,
    var uri: String,
    private val timeoutTime: Int
) {
    private var binder: MyWebSocketServiceBinder? = null
    private var mOnWebSocketOpenListener: OnWebSocketOpenListener? = null
    private val TAG = this::class.java.simpleName
    private val gson = Gson()

    interface OnWebSocketOpenListener {
        fun onOpen(handshakedata: ServerHandshake?)
    }

    private val mListener: WebSocketConnectionListener = object : WebSocketConnectionListener {
        override fun onOpen(handshakedata: ServerHandshake) {
            if (null != mOnWebSocketOpenListener) {
                mOnWebSocketOpenListener!!.onOpen(handshakedata)
            }
            MessageHelper.messageUnReadMap.clear()
            MessageHelper.applyUnReadMap.clear()
            RxBus.getInstance().post(WebSocketOpen())
        }

        override fun onMessage(message: String) {
            val jsonObject = JsonParser().parse(message).asJsonObject
            println(jsonObject)
            when (jsonObject.get("type").asString) {
                "OffLineMessage" -> {
                    Log.d(TAG, "聊天列表通知")
                    val bean = gson.fromJson(message, WSMessageResponse::class.java)
                    MessageHelper.onReceiveMessage(bean.data)
                    RxBus.getInstance().post(bean)
                }
                "OnLineMessage" -> {
                    Log.d(TAG, "在线聊天通知")
                    val bean = gson.fromJson(message, WSChatOnlineMessageResponse::class.java)
                    RxBus.getInstance().post(bean)
                }
                "Apply" -> {
                    Log.d(TAG, "好友添加通知")
                    val bean = gson.fromJson(message, WSApplyFriendResponse::class.java)
                    MessageHelper.onReceiveApply(bean.data)
                    RxBus.getInstance().post(bean)
                }
                "Account" -> {
                    Log.d(TAG, "黑名单")
                    val bean = gson.fromJson(message, WSAccountBan::class.java)
                    RxBus.getInstance().post(bean)
                }
            }
        }

        override fun onClose(
            code: Int,
            reason: String,
            remote: Boolean
        ) {
            Log.i("onClose", "code:" + code + ",reason:" + reason + "remote:" + remote)
            if (code == WebSocketService.USER_CLOSE_CODE && reason == "userClose") {
                return
            }
            Thread(Runnable {
                while (true) {
                    if (null != binder) {
                        println("in loop")
                        if (binder!!.isClosed) {
                            binder!!.connect()
                            println("connecting.....")
                        } else {
                            break
                        }
                    }
                }
            }).start()
        }

        override fun onError(ex: Exception) {
            ex.printStackTrace()
            if (binder != null) {
                binder!!.connect()
            }
        }
    }

    /**
     * 连接
     */
    fun connect(listener: OnWebSocketOpenListener?) {
        mOnWebSocketOpenListener = listener
        val intent = Intent(mContext, WebSocketService::class.java)
        binder?.changeUri(uri)
        intent.putExtra(WebSocketService.INTENT_DATA_URI, uri)
        intent.putExtra(WebSocketService.INTENT_DATA_TIMEOUT_TIME, timeoutTime)
        val connection: ServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(
                name: ComponentName,
                service: IBinder
            ) {
                binder = service as MyWebSocketServiceBinder
                binder!!.setConnectListener(mListener)
                binder!!.connect()
            }

            override fun onServiceDisconnected(name: ComponentName) {
                binder!!.close()
            }
        }
        mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)
    }

    /**
     * 发送数据
     *
     * @param msg 消息
     * @throws Exception [NotYetConnectedException] 当未连接时抛出异常
     */
    @Throws(Exception::class)
    fun sendMsg(msg: String?) {
        try {
            binder!!.sendMsg(msg)
        } catch (e: NotYetConnectedException) {
            throw RuntimeException(e)
        }
    }

    /**
     * 判断是否已连接
     *
     * @return 是否已连接
     */
    val isConnected: Boolean
        get() = binder!!.isConnecting

    /**
     * 断开连接
     */
    fun disConnect() {
        binder!!.close()
    }

    companion object {
        @SuppressLint("StaticFieldLeak")
        private var instance: WebSocketAndroidClient? = null
        const val INTENT_WEBSOCKET_MSG = "webSocketMsg"

        /**
         * 初始化
         *
         * @param context 上下文
         * @param uri     websocket 地址
         */
        fun init(context: Context, uri: String) {
            if (null == instance) {
                synchronized(WebSocketAndroidClient::class.java) {
                    if (null == instance) {
                        instance =
                            WebSocketAndroidClient(context, uri, 0)
                    }
                }
            }
        }

        /**
         * 初始化
         *
         * @param context     上下文
         * @param uri         websocket 地址
         * @param timeoutTime 超时时间
         */
        fun init(
            context: Context,
            uri: String,
            timeoutTime: Int
        ) {
            if (null == instance) {
                synchronized(WebSocketAndroidClient::class.java) {
                    if (null == instance) {
                        instance =
                            WebSocketAndroidClient(context, uri, timeoutTime)
                    }
                }
            }
        }

        fun getInstance(): WebSocketAndroidClient? {
            if (null == instance) {
                throw RuntimeException("WebSocketAndroidClient not init")
            }
            return instance
        }
    }

}